home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / smtpserv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-13  |  36.9 KB  |  1,535 lines

  1. /*  SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  *
  4.  * Mods by G1EMM, PA0GRI and KO4KS
  5.  */
  6. #include <stdio.h>
  7. #include <time.h>
  8. #ifdef UNIX
  9. #include <sys/types.h>
  10. #endif
  11. #if    defined(__STDC__) || defined(__TURBOC__)
  12. #include <stdarg.h>
  13. #endif
  14. #include <ctype.h>
  15. #include <setjmp.h>
  16. #include "global.h"
  17. #include "config.h"
  18. #include "mbuf.h"
  19. #include "cmdparse.h"
  20. #include "socket.h"
  21. #ifdef    LZW
  22. #include "lzw.h"
  23. #endif
  24. #include "iface.h"
  25. #include "proc.h"
  26. #include "smtp.h"
  27. #include "commands.h"
  28. #include "dirutil.h"
  29. #include "mailbox.h"
  30. #include "mailutil.h"
  31. #include "bm.h"
  32. #include "domain.h"
  33. #include "session.h"
  34. #include "mailfor.h"
  35. #ifdef  NNTPS
  36. #include "nntp.h"
  37. #endif
  38.  
  39. char *Days[7] = {  "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  40. char *Months[12] = { "Jan","Feb","Mar","Apr","May","Jun",
  41.         "Jul","Aug","Sep","Oct","Nov","Dec" };
  42.  
  43.  
  44.  
  45. char *host_or_wpage_exp __ARGS((char *to,int hier,int exphome));
  46. extern char *wpage_exp __ARGS((char *to,int hier,int exphome));
  47. extern FILE *fopennew __ARGS((char *fname, char *mode));
  48. struct list *expandalias __ARGS((struct list **head,char *user,char *orig));
  49. static int  getmsgtxt __ARGS((struct smtpsv *mp));
  50. static struct smtpsv *mail_create __ARGS((void));
  51. static void mail_clean __ARGS((struct smtpsv *mp));
  52. static int mailit __ARGS((FILE *data,char *from,struct list *tolist));
  53. static int router_queue __ARGS((FILE *data,char *from,struct list *to));
  54. static void smtplog __ARGS((char *fmt,...));
  55. static void smtpserv __ARGS((int s,void *unused,void *p));
  56. int mailuser __ARGS((FILE *data,char *from,char *to,char *origto));
  57. extern int msgidcheckg __ARGS((char *string));
  58. extern int rdaemon __ARGS((FILE *data,char *from,char *to,char *msg,char msgtype, int mode));
  59. #ifdef RMAIL
  60. extern int rmail __ARGS((FILE *fp, char *from));
  61. #endif
  62. #ifdef REQSVR
  63. extern int reqsvr __ARGS((FILE *fp, char *from));
  64. #endif
  65. extern FILE *subdir_fopen __ARGS((char *name, char *mode));
  66. extern char *nntp_name_expansion __ARGS((char *name));
  67.  
  68. /* Command table */
  69. static char *commands[] = {
  70.     "helo",
  71. #define    HELO_CMD    0
  72.     "noop",
  73. #define    NOOP_CMD    1
  74.     "mail from:",
  75. #define    MAIL_CMD    2
  76.     "quit",
  77. #define    QUIT_CMD    3
  78.     "rcpt to:",
  79. #define    RCPT_CMD    4
  80.     "help",
  81. #define    HELP_CMD    5
  82.     "data",
  83. #define    DATA_CMD    6
  84.     "rset",
  85. #define    RSET_CMD    7
  86.     "expn",
  87. #define EXPN_CMD    8
  88. #ifdef    LZW
  89.     "xlzw",
  90. #define XLZW_CMD    9
  91. #endif
  92.     NULLCHAR
  93. };
  94.  
  95. /* Reply messages */
  96. static char Banner[] = "220 %s SMTP ready\n";
  97. static char Closing[] = "221 Closing\n";
  98. static char Ok[] = "250 Ok\n";
  99. static char Reset[] = "250 Reset state\n";
  100. static char Sent[] = "250 Sent\n";
  101. static char Ourname[] = "250 %s, Share and Enjoy!\n";
  102. #ifdef    LZW
  103. static char LZWOk[] = "250 %d %d LZW Ok\n";
  104. static char Help[] = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN XLZW\n214 End\n";
  105. #else
  106. static char Help[] = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN\n214 End\n";
  107. #endif
  108. static char Enter[] = "354 Enter mail, end with .\n";
  109. static char DupBidMsg[] = "550 Duplicate BID found in Message-Id line\n";
  110. static char Lowmem[] = "421 System overloaded, try again later\n";
  111. static char Ioerr[] = "452 Temp file write error\n";
  112. static char Badcmd[] = "500 Command unrecognized\n";
  113. static char Syntax[] = "501 Syntax error\n";
  114. static char Needrcpt[] = "503 Need RCPT (recipient)\n";
  115. static char Unknown[] = "550 <%s> address unknown\n";
  116. static char Noalias[] = "550 No alias for <%s>\n";
  117. char DAEMONSTR[] = "%sMAILER-DAEMON@%s (Mail Delivery Subsystem)\n";
  118.  
  119. static int Ssmtp = -1; /* prototype socket for service */
  120. int MbHolding = 0;
  121. extern char *Historyfile;
  122. #ifdef WPAGES
  123. extern int MbWpages;
  124. #endif
  125. extern int Smtpbidcheck;
  126.  
  127. #ifdef    MSDOS
  128. /* Valid characters in a DOS filename matrix */
  129. static unsigned char doschars[] = {
  130.     0x00, 0x00, 0x00, 0x00, 0xfa, 0x23, 0xff, 0x03,
  131.     0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0x6f,
  132.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  133.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  134.     };
  135. static int dosfnchr __ARGS((int ch));
  136. #endif
  137.  
  138. /* Start up SMTP receiver service */
  139. int
  140. smtp1(argc,argv,p)
  141. int argc;
  142. char *argv[];
  143. void *p;
  144. {
  145.     return (installserver (argc, argv, &Ssmtp, "SMTP listener", IPPORT_SMTP,
  146.         "SMTP server", smtpserv, 2048, NULL));
  147. }
  148.  
  149. /* Shutdown SMTP service (existing connections are allowed to finish) */
  150. int
  151. smtp0(argc,argv,p)
  152. int argc;
  153. char *argv[];
  154. void *p;
  155. {
  156.     return (deleteserver (&Ssmtp));
  157. }
  158.  
  159. static void
  160. smtpserv(s,unused,p)
  161. int s;
  162. void *unused;
  163. void *p;
  164. {
  165.     struct smtpsv *mp;
  166.     char **cmdp,buf[LINELEN],*arg,*cp,*cmd,*newaddr;
  167.     struct list *ap,*list;
  168.     int cnt;
  169.     char address_type;
  170.         char *orig;
  171. #ifdef    LZW
  172.     extern int Smtpslzw;
  173.     int lzwbits, lzwmode;
  174. #endif
  175.  
  176.     sockmode(s,SOCK_ASCII);
  177.     sockowner(s,Curproc);        /* We own it now */
  178.     log(s,"open SMTP");
  179.  
  180.     if((mp = mail_create()) == NULLSMTPSV){
  181.         tprintf(Nospace);
  182.         log(s,"close SMTP - no space");
  183.         close_s(s);
  184.         return;
  185.     }
  186.     mp->s = s;
  187.  
  188.     (void) usprintf(s,Banner,Hostname);
  189.  
  190. loop:    pwait (NULL);
  191.     if ((cnt = recvline(s,buf,sizeof(buf))) == -1){
  192.         /* He closed on us */
  193.         goto quit;
  194.     }
  195.     if(cnt < 4){
  196.         /* Can't be a legal command */
  197.         usprintf(mp->s,Badcmd);
  198.         goto loop;
  199.     }    
  200.     rip(buf);
  201.     cmd = buf;
  202.  
  203.     /* Translate entire buffer to lower case */
  204.     for(cp = cmd;*cp != '\0';cp++)
  205.         *cp = tolower(*cp);
  206.  
  207.     /* Find command in table; if not present, return syntax error */
  208.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  209.         if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  210.             break;
  211.     if(*cmdp == NULLCHAR){
  212.         (void) usprintf(mp->s,Badcmd);
  213.         goto loop;
  214.     }
  215.     arg = &cmd[strlen(*cmdp)];
  216.     /* Skip spaces after command */
  217.     while(*arg == ' ')
  218.         arg++;
  219.     /* Execute specific command */
  220.     switch(cmdp-commands){
  221. #ifdef    LZW
  222.     case XLZW_CMD:
  223.         if(!Smtpslzw) {
  224.             usprintf(mp->s,Badcmd);
  225.         } else {
  226.             lzwmode = lzwbits = 0;
  227.             sscanf(arg,"%d %d",&lzwbits,&lzwmode);
  228.             if(!((lzwmode == 0 || lzwmode == 1)
  229.               && (lzwbits > 8 && lzwbits < 17))) {
  230.                 lzwmode = LZWCOMPACT;
  231.                 lzwbits = LZWBITS;
  232.                 usprintf(mp->s,Badcmd);
  233.             } else {
  234.                 usprintf(mp->s,LZWOk,lzwbits,lzwmode);
  235.                 lzwinit(mp->s,lzwbits,lzwmode);
  236.             }
  237.         }
  238.         break;
  239. #endif
  240.     case HELO_CMD:
  241.         free(mp->system);
  242.         mp->system = strdup(arg);
  243.         (void) usprintf(mp->s,Ourname,Hostname);
  244.         break;
  245.     case NOOP_CMD:
  246.         (void) usprintf(mp->s,Ok);
  247.         break;
  248.     case MAIL_CMD:
  249.         if((cp = getname(arg)) == NULLCHAR){
  250.             (void) usprintf(mp->s,Syntax);
  251.             break;
  252.         }
  253.         free(mp->from);
  254.         mp->from = strdup(cp);
  255.         (void) usprintf(mp->s,Ok);
  256.         break;
  257.     case QUIT_CMD:
  258.         (void) usprintf(mp->s,Closing);
  259.         goto quit;
  260.     case RCPT_CMD:    /* Specify recipient */
  261.         if((cp = getname(arg)) == NULLCHAR){
  262.             (void) usprintf(mp->s,Syntax);
  263.             break;
  264.         }
  265.         orig = strdup (cp);
  266.         /* rewrite address if possible */
  267.         if((newaddr = rewrite_address(cp)) != NULLCHAR){
  268.             strcpy(buf,newaddr);
  269.             cp = buf;
  270.             free(newaddr);
  271.         }
  272.  
  273.         /* check if address is ok */
  274.         if ((address_type = validate_address(cp)) == BADADDR){
  275.             (void) usprintf(mp->s,Unknown,cp);
  276.             free (orig);
  277.             break;
  278.         }
  279.         /* if a local address check for an alias */
  280.         if (address_type == LOCAL)
  281.             expandalias(&mp->to, cp, orig);
  282.         else
  283.             /* a remote address is added to the list */
  284.             addlist(&mp->to, cp, address_type, orig);
  285.  
  286.         (void) usprintf(mp->s,Ok);
  287.         free (orig);
  288.         break;
  289.     case HELP_CMD:
  290.         (void) usprintf(mp->s,Help);
  291.         break;
  292.     case DATA_CMD:
  293.         if(mp->to == NULLLIST)
  294.             (void) usprintf(mp->s,Needrcpt);
  295.         else if ((mp->data = tmpfile()) == NULLFILE)
  296.             (void) usprintf(mp->s,Ioerr);
  297.          else
  298.             getmsgtxt(mp);
  299.         break;
  300.     case RSET_CMD:
  301.         del_list(mp->to);
  302.         mp->to = NULLLIST;
  303.         (void) usprintf(mp->s,Reset);
  304.         break;
  305.     case EXPN_CMD:
  306.         if (*arg == '\0'){
  307.             (void) usprintf(mp->s,Syntax);
  308.             break;
  309.         }
  310.  
  311.         list = NULLLIST;
  312.         orig = strdup (arg);
  313.         /* rewrite address if possible */
  314.         if((newaddr = rewrite_address(arg)) != NULLCHAR)
  315.             if(strcmp(newaddr,arg) == 0){
  316.                 free(newaddr);
  317.                 newaddr = NULLCHAR;
  318.             } else {
  319.                 strcpy(buf,newaddr);
  320.                 arg = buf;
  321.             }
  322.         list = NULLLIST;
  323.         expandalias(&list,arg, orig);
  324.         free (orig);
  325.         if (strcmp(list->val,arg) == 0 && list->next == NULLLIST)
  326.             if(newaddr == NULLCHAR){
  327.                 (void) usprintf(mp->s,Noalias,arg);
  328.                 del_list(list);
  329.                 break;
  330.             }
  331.         ap = list;
  332.         while (ap->next != NULLLIST){
  333.             (void) usprintf(mp->s,"250-%s\n",ap->val);
  334.             ap = ap->next;
  335.         }
  336.         usprintf(mp->s,"250 %s\n",ap->val);
  337.         del_list(list);
  338.         free(newaddr);
  339.         break;
  340.     }
  341.     goto loop;
  342.  
  343. quit:
  344.     log(mp->s,"close SMTP");
  345.     close_s(mp->s);
  346.     mail_clean(mp);
  347.     smtptick(NULL);            /* start SMTP daemon immediately */
  348. }
  349.  
  350.  
  351. int
  352. makeBBSbid (bid, line, ours)
  353. char *bid, *line;
  354. int ours;
  355. {
  356. char *cp;
  357. int retval = 0;
  358.  
  359.     *bid = 0;
  360.     if((cp = getname(line)) == NULLCHAR)
  361.         return retval;
  362.     strcpy(bid,cp);
  363.     cp = strchr(bid,'@');
  364.     /* A trailing ".bbs" indicates that the Message-ID was generated
  365.      * from a BBS style message, and not a RFC-822 message.
  366.      */
  367.     if(cp != NULLCHAR && stricmp(&bid[strlen(bid) - 4], ".bbs") == 0) {
  368.         *cp = '\0'; /*retain the bid given by user*/
  369.         retval = 1;
  370.     } else {
  371.         if (ours)    {
  372.             /*This is a message with no bid, MSGID is <msg#@hostname>
  373.              *make this BID style 'msg#_host'
  374.              *ie. replace @ with _ and
  375.              *cut off after first part of hostname  - WG7J
  376.              */
  377.             *cp = '_';
  378.             if((cp = strchr(cp,'.')) != NULLCHAR)
  379.                 *cp = '\0';
  380.             retval = 1;
  381.         }
  382.     }
  383.     bid[13] = '\0'; /* BIDs should be no longer than 13 bytes */
  384.     return retval;
  385. }
  386.  
  387.  
  388. extern char shortversion[];
  389. extern char *Mbfwdinfo;
  390.  
  391. /* read the message text
  392.  * This now checks for Message-Id's that could be bids
  393.  * and deletes the message if so. - WG7J
  394.  */
  395. static int
  396. getmsgtxt(mp)
  397. struct smtpsv *mp;
  398. {
  399. char buf[LINELEN];
  400. register char *p = buf;
  401. long t;
  402. #ifdef MBFWD
  403. char *cp, *cp2;
  404. char bid[LINELEN];
  405. time_t now;
  406. FILE *fp;
  407. int foundbid = 0;
  408. #endif
  409.  
  410.     /* Add timestamp; ptime adds newline */
  411.     time(&t);
  412.     fprintf(mp->data,Hdrs[RECEIVED]);
  413.     if(mp->system != NULLCHAR)
  414.         fprintf(mp->data,"from %s ",mp->system);
  415. #ifdef MBFWD
  416.     fprintf(mp->data,"by %s (%s) with SMTP\n\tid AA%ld ; %s",
  417.             Hostname, (Mbfwdinfo != NULLCHAR) ? Mbfwdinfo : shortversion, \
  418.             get_msgid(0), ptime(&t));
  419. #else
  420.     fprintf(mp->data,"by %s (%s) with SMTP\n\tid AA%ld ; %s",
  421.             Hostname, shortversion, get_msgid(0), ptime(&t));
  422. #endif
  423.     if(ferror(mp->data))    {
  424.         (void) usprintf(mp->s,Ioerr);
  425.         return 1;
  426.     } else {
  427.         (void) usprintf(mp->s,Enter);
  428.     }
  429.     while(1)    {
  430.         pwait (NULL);
  431.         if(recvline(mp->s,p,sizeof(buf)) == -1)
  432.             return 1;
  433.         rip(p);
  434.         /* check for end of message ie a . or escaped .. */
  435.         if (*p == '.')    {
  436.             if (*++p == '\0')    {
  437. #ifdef MBFWD
  438.                 /* Also sends appropriate response */
  439.                 /* if duplicate BID, do not send - WG7J */
  440.                 if (mp->dupbid)
  441.                     (void) usputs(mp->s,DupBidMsg);
  442.                 else
  443. #endif
  444.                     if(mailit(mp->data,mp->from,mp->to) != 0)
  445.                         (void) usputs(mp->s,Ioerr);
  446.                 else
  447.                     (void) usprintf(mp->s,Sent);
  448.                 fclose(mp->data);
  449.                 mp->data = NULLFILE;
  450.                 del_list(mp->to);
  451.                 mp->to = NULLLIST;
  452. #ifdef MBFWD
  453.                         /* If there is a BID set, save it in the history file - WG7J */
  454.                         if(mp->bid != NULLCHAR)
  455.                             if((fp = fopennew(Historyfile,APPEND_TEXT)) != NULL) {
  456.                                 /* Timestamp added to allow automatic expiry
  457.                                  * of bid file - WG7J
  458.                                  */
  459.                                 time(&now);
  460.                                 fprintf(fp,"%-13.13s %-14ld\n",mp->bid,now); /* Save BID */
  461.                                 fclose(fp);
  462.                                 /* Free this bid ! */
  463.                                 free(mp->bid);
  464.                                 mp->bid = NULL;
  465.                             }
  466. #endif
  467.                 return 0;
  468.             } else if (!(*p == '.' && *(p+1) == '\0'))
  469.                 p--;
  470.         }
  471.         /* for UNIX mail compatiblity */
  472.         if (!strncmp(p,"From ",5))
  473.             (void) putc('>',mp->data);
  474.          /* Append to data file */
  475.         if(fprintf(mp->data,"%s\n",p) < 0)    {
  476.             (void) usprintf(mp->s,Ioerr);
  477.             return 1;
  478.         }
  479. #ifdef MBFWD
  480.         /* Check for Message-Id string - WG7J */
  481.         if(!foundbid && !strnicmp(p,Hdrs[MSGID], 11))     {
  482.             /* so we ignore any "Message ID:" in the text body,
  483.                which occurs when we are inserting a message */
  484.             foundbid = 1;
  485.             if (makeBBSbid (bid, p, 0))    {
  486.                 /* now check it */
  487.                 if (Smtpbidcheck && (mp->dupbid = msgidcheck(bid)) == 0)
  488.                         mp->bid = strdup(bid);
  489.                 }
  490.         }
  491. #endif
  492. #ifdef WPAGES
  493.         if(MbWpages && (!strnicmp(p,"R:",2)) && (*(p+8) == '/')) {    /* found one */
  494.             /* Find the '@[:]CALL.STATE.COUNTRY'or
  495.              * or the '?[:]CALL.STATE.COUNTRY' string
  496.              * The : is optional.     */
  497.             if( ((cp=strchr(p,'@')) != NULLCHAR) || ((cp=strchr(p,'?')) != NULLCHAR) ) {
  498.                 if((cp2=strpbrk(cp," \n\t")) != NULLCHAR)
  499.                     *cp2 = '\0';
  500.                 /* Some bbs's send @bbs instead of @:bbs*/
  501.                 if (*++cp == ':')
  502.                     cp++;
  503.                 pwait (NULL);        /* just to be nice to others */
  504.                 wpageAdd (cp, 1, 1);
  505.             }
  506.         }
  507. #endif
  508.     }
  509. }
  510.  
  511. /* Create control block, initialize */
  512. static struct smtpsv *
  513. mail_create()
  514. {
  515.     register struct smtpsv *mp;
  516.  
  517.     mp = (struct smtpsv *)callocw(1,sizeof(struct smtpsv));
  518.     mp->from = strdup("");    /* Default to null From address */
  519.     return mp;
  520. }
  521.  
  522. /* Free resources, delete control block */
  523. static void
  524. mail_clean(mp)
  525. register struct smtpsv *mp;
  526. {
  527.     if (mp == NULLSMTPSV)
  528.         return;
  529.     free(mp->system);
  530.     free(mp->from);
  531.     if(mp->data != NULLFILE)
  532.         fclose(mp->data);
  533.     del_list(mp->to);
  534.     free((char *)mp);
  535. }
  536.  
  537.  
  538. /* get status of an entry in the *.ctl file */
  539.  
  540. void
  541. statusCtl (who, extension, info, entry, readit)
  542. char *who, *extension;
  543. struct let *info;
  544. int entry, readit;
  545. {
  546. register FILE *fp;
  547. char mailbox[100];
  548. int oldstatus;
  549.  
  550.     sprintf(mailbox,"%s/CONTROL/%s.%s",Mailspool,who, extension);
  551.     if((fp = subdir_fopen(mailbox,(readit) ? READ_BINARY : UPDATE_TEXT)) != NULLFILE){
  552.         fseek (fp, (long) ((entry - 1) * sizeof (struct let)), 0);
  553.         if (readit)
  554.             fread (info, sizeof(struct let), 1, fp);
  555.         else    {
  556.             oldstatus = info->status;
  557.             if (issysarea (who))
  558.                 info->status &= ~BM_READ;
  559.             fwrite (info, sizeof(struct let), 1, fp);
  560.             info->status = oldstatus;
  561.         }
  562.         fclose(fp);
  563.     }
  564. }
  565.  
  566. /* handle updating of the *.ctl file, here */
  567.  
  568. void
  569. updateCtl (who, info)
  570. char *who;
  571. struct let *info;
  572. {
  573. register FILE *fp;
  574. char mailbox[100];
  575.  
  576.     pwait (NULL);
  577.     sprintf(mailbox,"%s/CONTROL/%s.ctl",Mailspool,who);
  578.     if((fp = subdir_fopen(mailbox,APPEND_BINARY)) != NULLFILE){
  579.         fwrite (info, sizeof(struct let), 1, fp);
  580.         fclose(fp);
  581.     }
  582. }
  583.  
  584.  
  585. /* handle updating of the *.fwd files, here */
  586.  
  587. void
  588. updateFwd (who, area, bid)
  589. char *who, *area;
  590. long bid;
  591. {
  592. register FILE *fp;
  593. char mailbox[100];
  594.  
  595.     pwait (NULL);
  596.     sprintf(mailbox,"%s/%s.fwd",Mailspool,who);
  597.     if((fp = fopen(mailbox,APPEND_TEXT)) != NULLFILE)    {
  598.         fprintf (fp, " %s %-ld\n", area, bid);
  599.         fclose(fp);
  600.     }
  601. }
  602.  
  603.  
  604. /* General mailit function. It takes a list of addresses which have already
  605. ** been verified and expanded for aliases. Base on the current mode the message
  606. ** is place in an mbox, the outbound smtp queue or the rqueue interface
  607. */
  608. static int
  609. mailit(data,from,tolist)
  610. FILE *data;
  611. char *from;
  612. struct list *tolist;
  613. {
  614. struct list *ap, *dlist = NULLLIST;
  615. FILE *fp, *out;
  616. char    mailbox[50], *cp, *host, *qhost;
  617. char forwardto[32];
  618. char origaddressee[40];
  619. int    c, fail = 0, lines, k;
  620. time_t    t;
  621. extern int Smtpquiet;
  622. int lastWasCR, wasForwarded;
  623. #ifdef USERLOG
  624. long msgid;
  625. int nextisBID;
  626. #endif
  627. char *realnm, *realarea;
  628. int index;
  629. int Holdit = 0, firstIDline;
  630.  
  631.     struct let lt;
  632.     long startedat, endedat;
  633.  
  634.     if ((Smtpmode & QUEUE) != 0)
  635.         return(router_queue(data,from,tolist));
  636.  
  637.     do {
  638.         qhost = NULLCHAR;
  639.         for(ap = tolist;ap != NULLLIST;ap = ap->next)
  640.             if (ap->type == DOMAIN){
  641.                 if ((host = strrchr(ap->val,'@')) != NULLCHAR)
  642.                     host++;
  643.                 else
  644.                     host = Hostname;
  645.                 if(qhost == NULLCHAR)
  646.                          qhost = host;
  647.                 if(stricmp(qhost,host) == 0){
  648.                     ap->type = BADADDR;
  649.                     addlist(&dlist,ap->val,0, ap->val);
  650.                 }
  651.             }
  652.         if(qhost != NULLCHAR){
  653.             rewind(data);
  654.             queuejob(data,qhost,dlist,from);
  655.             del_list(dlist);
  656.             dlist = NULLLIST;
  657.         }
  658.     } while(qhost != NULLCHAR);
  659.  
  660. #ifdef    NNTPS
  661.     for(ap = tolist;ap != NULLLIST;ap = ap->next){
  662.         if(ap->type != NNTP_GATE)
  663.             continue;
  664.         nnGpost(data,from,ap);
  665.         ap->type = BADADDR;
  666.     }
  667. #endif
  668.  
  669.     index = 0;
  670.     for(ap = tolist;ap != NULLLIST;ap = ap->next,index++){
  671.         if(ap->type != LOCAL){
  672.             ap->type = DOMAIN;
  673.             continue;
  674.         }
  675.         /* If local rewrite to CHECK, then tell SYSOP */
  676.         if (!stricmp (ap->val, "check"))    {
  677.             rewind (data);
  678.             rdaemon (data, NULLCHAR, NULLCHAR, "Unknown Routing", 'P', 1);
  679.         }
  680. #ifdef RMAIL
  681.         /* If local RMAIL, then leave here */
  682.         if (!stricmp (ap->val, "rmail"))        {
  683.             if (rmail (data, from))
  684.                 continue;    /* if handled by rmail() */
  685.         }
  686. #endif
  687. #ifdef REQSVR
  688.         /* If local REQSVR, then see if this is one supported */
  689.         if (!stricmp (ap->val, "reqsvr"))        {
  690.             if (reqsvr (data, from))
  691.                 continue;    /* if handled by reqsvr() */
  692.         }
  693. #endif
  694.         /* strip off host name of LOCAL addresses */
  695.         if ((cp = strchr(ap->val,'@')) != NULLCHAR)
  696.             *cp = '\0';
  697.  
  698.         rewind(data);
  699.         /* replace '\' and '.' with '/',
  700.          * this allows mailing into subdirs of spool/mail - WG7J
  701.          */
  702.         cp = ap->val;
  703.         while((cp=strchr(cp,'.')) != NULLCHAR)
  704.             *cp++ = '/';
  705.         cp = ap->val;
  706.         while((cp=strchr(cp,'\\')) != NULLCHAR)
  707.             *cp++ = '/';
  708.  
  709.         /* truncate long user names */
  710. /*        if (strlen(ap->val) > MBOXLEN)
  711.              ap->val[MBOXLEN] = '\0';
  712.  */
  713.  
  714.         if ((realarea = rewrite_address (ap->orig)) == NULLCHAR)
  715.             realarea = strdup (ap->val);
  716.  
  717.         /* if mail file is busy save it in our smtp queue
  718.          * and let the smtp daemon try later.
  719.          */
  720.         if (mlock(Mailspool,realarea)){
  721.             addlist(&dlist,realarea,0, realarea);
  722.             fail = queuejob(data,Hostname,dlist,from);
  723.             del_list(dlist);
  724.             dlist = NULLLIST;
  725.             free (realarea);
  726.         } else {
  727.             char buf[LINELEN];
  728.             int tocnt = 0;
  729.             int chkwpages = 1;
  730.             sprintf(mailbox,"%s/%s",Mailspool,realarea);
  731.             nntp_name_expansion (mailbox);
  732.             strcat(mailbox,".txt");
  733. #ifndef    AMIGA
  734.             if((fp = subdir_fopen(mailbox,APPEND_TEXT)) != NULLFILE){
  735. #else
  736.             if((fp = subdir_fopen(mailbox,"r+")) != NULLFILE){
  737. #endif
  738.                 pwait (NULL);
  739.                 (void) fseek(fp, 0L, 2);
  740.                 time(&t);
  741. #ifdef USERLOG
  742.                 wasForwarded = nextisBID = firstIDline = 0;
  743.                 origaddressee[0] = 0;
  744.                 msgid = 0;
  745.                 lines = 0;
  746.                 for (k = 0; k < 32; k++)
  747.                     forwardto[k] = 0;
  748. #endif
  749.                 startedat = ftell(fp);
  750.                 fprintf(fp,"From %s %s",from,ctime(&t));
  751.                 host = NULLCHAR;
  752.                 while(fgets(buf,sizeof(buf),data) != NULLCHAR){
  753.                     pwait (NULL);
  754. #ifndef TNOS_68K
  755.                     lines++;
  756. #endif
  757.                     if(buf[0] == '\n'){
  758.                         if(tocnt == 0)    {
  759.                             fprintf(fp,"%s%s\n",Hdrs[APPARTO],ap->orig);
  760. #ifndef TNOS_68K
  761.                             lines++;
  762. #endif
  763.                         }
  764.                         fputc('\n',fp);
  765.                         break;
  766.                     }
  767.                     rip(buf);
  768.                     if (htype(buf) == TO)    {
  769.                         strncpy (origaddressee, &buf[4], 40);
  770.                         origaddressee[39] = 0;
  771.                         if (isgroup (origaddressee))    {
  772.                             fprintf (fp, "%s%s@%s\n%s%s-relay@%s\n%s%s-admin@%s\n",  Hdrs[XMAILGROUP], origaddressee, Hostname, Hdrs[SENDER], origaddressee, Hostname, Hdrs[ERRORSTO], origaddressee, Hostname);
  773. #ifndef TNOS_68K
  774.                             lines += 2;
  775. #endif
  776.                         }
  777.                         if (chkwpages)
  778.                             realnm = wpage_exp (strdup (ap->orig), 1, 0);
  779.                         else
  780.                             realnm = strdup (ap->orig);
  781.                         fprintf (fp, "%s%s", Hdrs[TO], realnm);
  782.                         free (realnm);
  783.                     } else if (htype(buf) == MSGID)    {
  784.                         long nerf;
  785.                         if (index)    {
  786. #if 0
  787.                             msgid = get_msgid(1);
  788.                             fprintf (fp, "%s<%ld@%s>",Hdrs[MSGID],msgid,Hostname);
  789. #else
  790.                             nerf = get_msgid(1);
  791.                             fprintf (fp, "%s<%ld@%s>",Hdrs[MSGID],nerf,Hostname);
  792. #endif
  793.                         } else    {
  794.                             cp = &buf[strlen(Hdrs[MSGID])];
  795.                             if (*cp == '<')
  796.                                 cp++;
  797.                             nerf = atol(cp);
  798. #if 0
  799.                             if (nerf)
  800.                                 msgid = nerf;
  801. #endif
  802.                             fputs(buf, fp);
  803.                         }
  804.                     } else
  805.                         fputs(buf, fp);
  806. #ifdef USERLOG
  807.                     if (!firstIDline && nextisBID && (cp=strstr(buf,"AA")) != NULLCHAR) {
  808.                         /*what follows is the message-number*/
  809.                         msgid = atol(cp+2);
  810.                         nextisBID = 0;
  811.                         firstIDline = 1;
  812.                     }
  813. #endif                        
  814.                     switch(htype(buf)){
  815.                     case XFORWARD:     k = BBSlookup (&buf[strlen(Hdrs[XFORWARD])]);
  816.                             if (k != -1)
  817.                                 forwardto[k] = 1;
  818.                             wasForwarded = 1;
  819.                             break;
  820.                     case RECEIVED:  
  821. #ifdef USERLOG
  822.                                nextisBID = 1;
  823. #endif
  824.                                break;
  825.                     case BBSTYPE:  
  826.                                chkwpages = 0;
  827.                                break;
  828.                     case XBBSHOLD:    {
  829.                             long here;
  830.                             here = ftell (data);
  831.                             rewind (data);
  832.                             rdaemon (data, NULLCHAR, NULLCHAR, "Held Message - Forward Loop", 'P', 1);
  833.                             fseek (data, here, SEEK_SET);
  834.                             Holdit = 1;
  835.                             }
  836.                             break;
  837.                     case CC:    if (origaddressee[0])    {
  838.                                 if ((cp = strchr (origaddressee, '.')) != NULLCHAR)
  839.                                     *cp = 0;
  840.                                 fprintf (fp, ", %s", origaddressee);
  841.                             }
  842.                     case TO:
  843.                         ++tocnt;
  844.                         break;
  845.                     case RRECEIPT:
  846.                         if((cp = getaddress(buf,0))
  847.                            != NULLCHAR){
  848.                             free(host);
  849.                             host = strdup(cp);
  850.                         }
  851.                         break;
  852.                     }
  853.                     fputc('\n', fp);
  854.                 }
  855.                 while(fgets(buf,sizeof(buf),data) != NULLCHAR)    {
  856.                     pwait (NULL);
  857.                     fputs(buf,fp);
  858. #ifndef TNOS_68K
  859.                     lines++;
  860. #endif
  861.                     lastWasCR = (buf[0] == '\n') ? 1 : 0;
  862.                     }
  863.                 if(ferror(fp))
  864.                     fail = 1;
  865.                 else if (!lastWasCR)    {
  866.                     fprintf(fp,"\n");
  867. #ifndef TNOS_68K
  868.                     lines++;
  869. #endif
  870.                 }
  871.                 /* Leave a blank line between msgs */
  872. #ifdef USERLOG
  873.                 fflush (fp);
  874.                 endedat = ftell (fp);
  875. #endif
  876.                 fclose(fp);
  877.  
  878. #ifdef USERLOG
  879.             lt.size = (endedat - startedat - lines - 1);
  880.             lt.status = ((isarea (realarea) && MbHolding && !wasForwarded) || Holdit) ? BM_ONHOLD : 0;
  881.             lt.start = startedat;
  882.             lt.bid = msgid;
  883.             updateCtl (realarea, <);
  884. #endif
  885.             if (msgid)
  886.                 for (k = 0; k < Numfwds; k++)
  887.                     if ((!forwardto[k]) && AREAlookup (realarea, k))
  888.                         updateFwd (MyFwds[k], realarea, lt.bid);
  889.  
  890. /* If we use tprintf here, instead of printf, flowcontrol
  891.  * in the command screen is used; if the system is unattended for
  892.  * more then 24 messages coming in, it will lock up mail delivery.
  893.  * Make sure this only goes to the command screen - WG7J
  894.  */
  895.                     if(Current->output == Command->output)
  896.                         printf("New mail for %s from <%s>%c\n",realarea,from, Smtpquiet ? ' ' : '\007');
  897.             if(host != NULLCHAR){
  898.                 rewind(data); /* Send return receipt */
  899.                 mdaemon(data,host,NULLLIST,0);
  900.                 free(host);
  901.                 }
  902.             } else 
  903.                 fail = 1;
  904.             (void) rmlock(Mailspool,realarea);
  905.             if (fail)
  906.                 break;
  907.             smtplog("deliver: To: %s From: %s Size: %ld",realarea,from, lt.size);
  908.             free (realarea);
  909.         }
  910.     }
  911.     return fail;
  912. }
  913.  
  914. /* Return Date/Time in Arpanet format in passed string */
  915. char *
  916. ptime(t)
  917. long *t;
  918. {
  919.     /* Print out the time and date field as
  920.      *        "DAY day MONTH year hh:mm:ss ZONE"
  921.      */
  922.     register struct tm *ltm;
  923.     static char tz[4];
  924.     static char str[40];
  925.     char *p, *getenv();
  926.     /* Read the system time */
  927.     ltm = localtime(t);
  928.  
  929.     if (*tz == '\0')
  930.         if ((p = getenv("TZ")) == NULL)
  931.             strcpy(tz,"UTC");
  932.         else
  933.             strncpy(tz,p,3);
  934.  
  935.     /* rfc 822 format */
  936.     sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  937.         Days[ltm->tm_wday],
  938.         ltm->tm_mday,
  939.         Months[ltm->tm_mon],
  940.         ltm->tm_year,
  941.         ltm->tm_hour,
  942.         ltm->tm_min,
  943.         ltm->tm_sec,
  944.         tz);
  945.     return(str);
  946. }
  947.  
  948. long 
  949. get_msgid(type)
  950. int type;    /* is this a sequence number (0) or a MID (1)? */
  951. {
  952.     char sfilename[LINELEN];
  953.     char s[20];
  954.     register long sequence = 0;
  955.     FILE *sfile;
  956.  
  957.     sprintf(sfilename,"%s/%s.seq",Mailqdir, (type) ? "message" : "sequence");
  958.     sfile = fopen(sfilename,READ_TEXT);
  959.  
  960.     /* if sequence file exists, get the value, otherwise set it */
  961.     if (sfile != NULL){
  962.         (void) fgets(s,sizeof(s),sfile);
  963.         sequence = atol(s);
  964.         if (type)    {    /* use 1-65535, only */
  965.             /* Keep it in range of and 5 digit number to use for dos name prefix with room to spare. */
  966.             if (sequence < 0L || sequence > 65534L )
  967.                 sequence = 0;
  968.         } else    {
  969.             /* Keep it in range of and 8 digit number to use for dos name prefix. */
  970.             if (sequence < 0L || sequence > 99999998L )
  971.                 sequence = 0;
  972.         }
  973.         fclose(sfile);
  974.     }
  975.  
  976.     /* increment sequence number, and write to sequence file */
  977.     sfile = fopen(sfilename,WRITE_TEXT);
  978.     fprintf(sfile,"%ld",++sequence);
  979.     fclose(sfile);
  980.     return sequence;
  981. }
  982.  
  983. /* test if mail address is valid */
  984. int
  985. validate_address(s)
  986. char *s;
  987. {
  988.     char *cp;
  989.     int32 addr;
  990.  
  991.     if(*s == '!'){
  992. #ifdef    NNTPS
  993.         if((cp = strpbrk(s,"%@.,/")) != NULLCHAR)
  994.             *cp = '\0';
  995.         return NNTP_GATE;
  996. #else
  997.         return BADADDR;
  998. #endif
  999.     }
  1000.     /* if address has @ in it then check dest address */
  1001.     if ((cp = strrchr(s,'@')) != NULLCHAR){
  1002.         cp++;
  1003.         /* 1st check if it is our hostname.
  1004.         * if not then check the hosts file and see if we can
  1005.         * resolve the address to a known site or one of our aliases.
  1006.         */
  1007.         if(stricmp(cp,Hostname) != 0){
  1008.             if ((addr = mailroute(cp)) == 0
  1009.                 && (Smtpmode & QUEUE) == 0)
  1010.                 return BADADDR;
  1011.             if (ismyaddr(addr) == NULLIF)
  1012.                 return DOMAIN;
  1013.         }
  1014.         
  1015.         /* on a local address remove the host name part */
  1016.         *--cp = '\0';
  1017.     }
  1018.  
  1019.     /* if using an external router leave address alone */
  1020.     if ((Smtpmode & QUEUE) != 0)
  1021.         return LOCAL;
  1022.  
  1023.     /* check for the user%host hack */
  1024.     if ((cp = strrchr(s,'%')) != NULLCHAR){
  1025.         *cp = '@';
  1026.         cp++;
  1027.         /* reroute based on host name following the % seperator */
  1028.         if (mailroute(cp) == 0)
  1029.             return BADADDR;
  1030.         else
  1031.             return DOMAIN;
  1032.     }
  1033.  
  1034. #ifdef MSDOS    /* dos file name checks */
  1035.     /* Check for characters illegal in MS-DOS file names */
  1036.     for(cp = s;*cp != '\0';cp++)    {
  1037.         /* Accept '.', '/', and '\' !
  1038.          * that way we can mail into subdirs - WG7J
  1039.          */
  1040.         if(*cp == '.' || *cp == '\\' || *cp == '/')
  1041.             continue;
  1042.         if(dosfnchr(*cp) == 0)
  1043.             return BADADDR;    
  1044.     }
  1045. #endif
  1046.     return LOCAL;
  1047. }
  1048.  
  1049. /* place a mail job in the outbound queue */
  1050. int
  1051. queuejob(dfile,host,to,from)
  1052. register FILE *dfile;
  1053. char *host;
  1054. struct list *to;
  1055. char *from;
  1056. {
  1057.     register FILE *fp;
  1058.     struct list *ap;
  1059.     char tmpstring[50], prefix[9], buf[LINELEN];
  1060.     register int cnt;
  1061.     long totalcnt = 0;
  1062.  
  1063.     sprintf(prefix,"%ld",get_msgid(0));
  1064.     mlock(Mailqdir,prefix);
  1065.     sprintf(tmpstring,"%s/%s.txt",Mailqdir,prefix);
  1066.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE){
  1067.         (void) rmlock(Mailqdir,prefix);
  1068.         return 1;
  1069.     }
  1070.     while((cnt = fread(buf, 1, LINELEN, dfile)) > 0)    {
  1071.         totalcnt += cnt;
  1072.         pwait (NULL);
  1073.         if(fwrite(buf, 1, cnt, fp) != cnt)
  1074.             break;
  1075.     }
  1076.     if(ferror(fp)){
  1077.         fclose(fp);
  1078.         (void) rmlock(Mailqdir,prefix);
  1079.         return 1;
  1080.     }
  1081.     fclose(fp);
  1082.     sprintf(tmpstring,"%s/%s.wrk",Mailqdir,prefix);
  1083.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE){
  1084.         (void) rmlock(Mailqdir,prefix);
  1085.         return 1;
  1086.     }
  1087.     pwait (NULL);
  1088.     fprintf(fp,"%s\n%s\n",host,from);
  1089.     for(ap = to; ap != NULLLIST; ap = ap->next){
  1090.         fprintf(fp,"%s\n",ap->val);
  1091.         smtplog("queue job %s To: %s From: %s Size: %ld",prefix,ap->val,from, totalcnt);
  1092.     }
  1093.     fclose(fp);
  1094.     (void) rmlock(Mailqdir,prefix);
  1095.     return 0;
  1096. }
  1097.  
  1098. /* Deliver mail to the appropriate mail boxes */
  1099. static int
  1100. router_queue(data,from,to)
  1101. FILE *data;
  1102. char *from;
  1103. struct list *to;
  1104. {
  1105.     int c;
  1106.     register struct list *ap;
  1107.     FILE *fp;
  1108.     char tmpstring[50];
  1109.     char prefix[9];
  1110.  
  1111.     sprintf(prefix,"%ld",get_msgid(0));
  1112.     mlock(Routeqdir,prefix);
  1113.     sprintf(tmpstring,"%s/%s.txt",Routeqdir,prefix);
  1114.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE){
  1115.         (void) rmlock(Routeqdir,prefix);
  1116.         return 1;
  1117.     }
  1118.     rewind(data);
  1119.     pwait (NULL);
  1120.     while((c = getc(data)) != EOF)
  1121.         if(putc(c,fp) == EOF)
  1122.             break;
  1123.     pwait (NULL);
  1124.     if(ferror(fp)){
  1125.         fclose(fp);
  1126.         (void) rmlock(Routeqdir,prefix);
  1127.         return 1;
  1128.     }
  1129.     fclose(fp);
  1130.     sprintf(tmpstring,"%s/%s.wrk",Routeqdir,prefix);
  1131.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE){
  1132.         (void) rmlock(Routeqdir,prefix);
  1133.         return 1;
  1134.     }
  1135.     fprintf(fp,"From: %s\n",from);
  1136.     for(ap = to;ap != NULLLIST;ap = ap->next){
  1137.         fprintf(fp,"To: %s\n",ap->val);
  1138.     }
  1139.     fclose(fp);
  1140.     (void) rmlock(Routeqdir,prefix);
  1141.     smtplog("rqueue job %s From: %s",prefix,from);
  1142.     return 0;
  1143. }
  1144.  
  1145. /* add an element to the front of the list pointed to by head 
  1146. ** return NULLLIST if out of memory.
  1147. */
  1148. struct list *
  1149. addlist(head,val,type,orig)
  1150. struct list **head;
  1151. char *val, *orig;
  1152. int type;
  1153. {
  1154. register struct list *tp;
  1155.  
  1156.     tp = (struct list *)callocw(1,sizeof(struct list));
  1157.  
  1158.     tp->next = NULLLIST;
  1159.  
  1160.     /* allocate storage for the char string */
  1161.     tp->val = strdup(val);
  1162.     tp->type = type;
  1163.     tp->orig = strdup (orig);
  1164.  
  1165.     /* add entry to front of existing list */
  1166.     if (*head == NULLLIST)
  1167.         *head = tp;
  1168.     else {
  1169.         tp->next = *head;
  1170.         *head = tp;
  1171.     }
  1172.     return tp;
  1173.  
  1174. }
  1175.  
  1176. int
  1177. isanIPhost (str)
  1178. char *str;
  1179. {
  1180. char *host;
  1181.  
  1182.     /* this routine returns 1 if it looks like an IP hostname,
  1183.        otherwise it returns 0 which means it is probably an AX25 BBS name */
  1184.     if (strstr (str, ".org") && strstr (str, ".com") &&
  1185.         strstr (str, ".gov") && strstr (str, ".mil") &&
  1186.         strstr (str, ".net") && strstr (str, ".edu"))
  1187.             return 1;
  1188.     if ((host = strchr (str, '@')) != 0)
  1189.         host++;
  1190.     else
  1191.         host = str;
  1192.     if(resolve(host))
  1193.         return 1;
  1194.     return 0;
  1195. }
  1196.  
  1197.  
  1198. char *
  1199. host_or_wpage_exp (to, hier, exphome)
  1200. char *to;
  1201. int hier;
  1202. int exphome;    /* append and expand home bbs name ? */
  1203. {
  1204.     if (isanIPhost (to))
  1205.         return (to);
  1206.     return (wpage_exp (to, hier, exphome));
  1207. }
  1208.  
  1209.  
  1210. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  1211. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  1212.  
  1213. /* check for a group and expand group into an address list */
  1214. static struct list *
  1215. expandgroup(head, user, orig)
  1216. struct list **head;
  1217. char *user, *orig;
  1218. {
  1219. FILE *fp;
  1220. register char *s,*p;
  1221. struct rr *rrp, *rrlp;
  1222. int ingroup = 0;
  1223. struct list *tp;
  1224. char buf[LINELEN], *t;
  1225.     
  1226.     /* no group file found */
  1227.     if ((fp = fopen(Group, READ_TEXT)) != NULLFILE)        {
  1228.         while (fgets(buf,LINELEN,fp) != NULLCHAR){
  1229.             pwait (NULL);
  1230.             p = buf;
  1231.             if (*p == '#' || *p == '\n')
  1232.                 continue;
  1233.             rip(p);
  1234.  
  1235.             /* if not in an matching entry skip continuation lines */
  1236.             if (!ingroup && isspace(*p))
  1237.                 continue;
  1238.  
  1239.             /* when processing an active group check for a continuation */
  1240.             if (ingroup){
  1241.                 if (!isspace(*p)) 
  1242.                     break;    /* done */
  1243.                 SKIPSPACE(p);
  1244.                 s = p;
  1245.                 SKIPWORD(p);
  1246.                 if (*p != '\0')
  1247.                     *p++ = '\0';
  1248.                 SKIPSPACE(p);
  1249.                 if (*p != 'S')
  1250.                     continue;
  1251.                 /* find hostname */
  1252. #ifdef    NNTPS
  1253.                 if(*s == '!')
  1254.                     tp = addlist(head,s,NNTP_GATE, s);
  1255.                 else
  1256. #endif
  1257.                 if (strchr(s,'@') != NULLCHAR)
  1258.                     tp = addlist(head,s,DOMAIN, s);
  1259.                 else    {
  1260.                     t = wpage_exp (strdup (s), 0, 0);
  1261.                     tp = addlist(head,t,LOCAL, t);
  1262.                     free (t);
  1263.                 }
  1264.             } else {
  1265.                 s = p;
  1266.                 if ((p = strchr (s, ':')) == NULLCHAR)    /* say what! */
  1267.                     continue;
  1268.                 *p = '\0';    /* end the group name */
  1269.                 if (strcmp(s,user) != 0)
  1270.                     continue;    /* no match go on */
  1271.                 ingroup = 1;
  1272.             }
  1273.         }
  1274.     }
  1275.  
  1276.     pwait (NULL);
  1277.     if (fp)
  1278.         (void) fclose(fp);
  1279.     if (ingroup)    /* found and processed an group. */
  1280.         return tp;
  1281.  
  1282.     /* no group found treat as a local address */
  1283.     return addlist(head, user, LOCAL, orig);
  1284. }
  1285.  
  1286. /* check for and alias and expand alias into a address list */
  1287. struct list *
  1288. expandalias(head, user, orig)
  1289. struct list **head;
  1290. char *user, *orig;
  1291. {
  1292.     FILE *fp;
  1293.     register char *s,*p;
  1294.     struct rr *rrp, *rrlp;
  1295.     int inalias = 0;
  1296.     struct list *tp;
  1297.     char buf[LINELEN], *t;
  1298.     
  1299.     /* no alias file found */
  1300.     if ((fp = fopen(Alias, READ_TEXT)) == NULLFILE){
  1301.         /* Try MB, MG or MR domain name records */
  1302.         rrlp = rrp = resolve_mailb(user);
  1303.         while(rrp != NULLRR){
  1304.             if(rrp->rdlength > 0){
  1305.                 /* remove the trailing dot */
  1306.                 rrp->rdata.name[rrp->rdlength-1] = '\0';
  1307.                 /* replace first dot with @ if there is no @ */
  1308.                 if(strchr(rrp->rdata.name,'@') == NULLCHAR
  1309.                    && (p = strchr(rrp->rdata.name,'.')) !=
  1310.                    NULLCHAR)
  1311.                     *p = '@';
  1312.                 if(strchr(rrp->rdata.name,'@') != NULLCHAR)
  1313.                     tp = addlist(head,rrp->rdata.name,
  1314.                              DOMAIN, rrp->rdata.name);
  1315.                 else
  1316.                     tp = addlist(head,rrp->rdata.name,
  1317.                              LOCAL, rrp->rdata.name);
  1318.                 ++inalias;
  1319.             }
  1320.             rrp = rrp->next;
  1321.         }
  1322.         free_rr(rrlp);
  1323.         if(inalias)
  1324.             return tp;
  1325.         else
  1326.             return expandgroup(head, user, orig);
  1327.     }
  1328.  
  1329.     while (fgets(buf,LINELEN,fp) != NULLCHAR){
  1330.         p = buf;
  1331.         if ( *p == '#' || *p == '\0' || *p == '\n')
  1332.             continue;
  1333.         rip(p);
  1334.  
  1335.         /* if not in an matching entry skip continuation lines */
  1336.         if (!inalias && isspace(*p))
  1337.             continue;
  1338.  
  1339.         /* when processing an active alias check for a continuation */
  1340.         if (inalias){
  1341.             if (!isspace(*p)) 
  1342.                 break;    /* done */
  1343.         } else {
  1344.             s = p;
  1345.             SKIPWORD(p);
  1346.             *p++ = '\0';    /* end the alias name */
  1347.             if (strcmp(s,user) != 0)
  1348.                 continue;    /* no match go on */
  1349.             inalias = 1;
  1350.         }
  1351.  
  1352.         /* process the recipients on the alias line */
  1353.         SKIPSPACE(p);
  1354.         while(*p != '\0' && *p != '#'){
  1355.             s = p;
  1356.             SKIPWORD(p);
  1357.             if (*p != '\0')
  1358.                 *p++ = '\0';
  1359.  
  1360.             /* find hostname */
  1361. #ifdef    NNTPS
  1362.             if(*s == '!')
  1363.                 tp = addlist(head,s,NNTP_GATE, s);
  1364.             else
  1365. #endif
  1366.             if (strchr(s,'@') != NULLCHAR)
  1367.                 tp = addlist(head,s,DOMAIN, s);
  1368.             else    {
  1369.                 t = wpage_exp (strdup (s), 0, 0);
  1370.                 tp = addlist(head,t,LOCAL, t);
  1371.                 free (t);
  1372.             }
  1373.             SKIPSPACE(p);
  1374.         }
  1375.     }
  1376.     (void) fclose(fp);
  1377.  
  1378.     if (inalias)    /* found and processed an alias. */
  1379.         return tp;
  1380.  
  1381.     /* no alias found treat as a local address */
  1382.     return expandgroup(head, user, orig);
  1383. }
  1384.  
  1385. #if    defined(ANSIPROTO)
  1386. static void
  1387. smtplog(char *fmt, ...)
  1388. {
  1389.     va_list ap;
  1390.     char *cp;
  1391.     long t;
  1392.     FILE *fp;
  1393.  
  1394.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  1395.         return;
  1396.     time(&t);
  1397.     cp = ctime(&t);
  1398.     rip(cp);
  1399.     fprintf(fp,"%s ",cp);
  1400.     va_start(ap,fmt);
  1401.     vfprintf(fp,fmt,ap);
  1402.     va_end(ap);
  1403.     fprintf(fp,"\n");
  1404.     fclose(fp);
  1405. }
  1406.  
  1407. #else
  1408.  
  1409. static void
  1410. smtplog(fmt,arg1,arg2,arg3,arg4)
  1411. char *fmt;
  1412. int arg1,arg2,arg3,arg4;
  1413. {
  1414.     char *cp;
  1415.     long t;
  1416.     FILE *fp;
  1417.  
  1418.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  1419.         return;
  1420.     time(&t);
  1421.     cp = ctime(&t);
  1422.     rip(cp);
  1423.     fprintf(fp,"%s ",cp);
  1424.     fprintf(fp,fmt,arg1,arg2,arg3,arg4);
  1425.     fprintf(fp,"\n");
  1426.     fclose(fp);
  1427. }
  1428. #endif
  1429.  
  1430. /* send mail to a single user. Can be called from the ax25 mailbox or
  1431. ** from the return mail function in the smtp client 
  1432. */
  1433. int
  1434. mailuser(data,from,to, origto)
  1435. FILE *data;
  1436. char *from;
  1437. char *to, *origto;
  1438. {
  1439.  
  1440.         int address_type, ret;
  1441.         struct list *tolist = NULLLIST;
  1442.  
  1443.         /* check if address is ok */
  1444.         if ((address_type = validate_address(to)) == BADADDR){
  1445.              return 1;
  1446.         }
  1447.         /* if a local address check for an alias */
  1448.         if (address_type == LOCAL)
  1449.             expandalias(&tolist, to, origto);
  1450.         else
  1451.             /* a remote address is added to the list */
  1452.             addlist(&tolist, to, address_type, origto);
  1453.         ret = mailit(data,from,tolist);
  1454.         del_list(tolist);
  1455.         return ret;
  1456.  
  1457. }
  1458.  
  1459. /* Mailer daemon return mail mechanism */
  1460. int
  1461. mdaemon(data,to,lp,bounce)
  1462. FILE *data;        /* pointer to rewound data file */
  1463. char *to;        /* Overridden by Errors-To: line if bounce is true */
  1464. struct list *lp;    /* error log for failed mail */
  1465. int bounce;        /* True for failed mail, otherwise return receipt */
  1466. {
  1467.     time_t t;
  1468.     FILE *tfile;
  1469.     char buf[LINELEN], *cp, *newto = NULLCHAR;
  1470.     int cnt;
  1471.     if(to == NULLCHAR || (to != NULLCHAR && *to == '\0') || bounce){
  1472.         while(fgets(buf,sizeof(buf),data) != NULLCHAR){
  1473.             if(buf[0] == '\n')
  1474.                 break;
  1475.             /* Look for Errors-To: */
  1476.             if(htype(buf) == ERRORSTO &&
  1477.                (cp = getaddress(buf,0)) != NULLCHAR){
  1478.                 free(newto);
  1479.                 newto = strdup(cp);
  1480.                 break;
  1481.             }
  1482.         }
  1483.         if(newto == NULLCHAR && ((to != NULLCHAR && *to == '\0') ||
  1484.            to == NULLCHAR))
  1485.             return -1;
  1486.         rewind(data);
  1487.     }
  1488.     if((tfile = tmpfile()) == NULLFILE)
  1489.         return -1;
  1490.     time(&t);
  1491.     fprintf(tfile,"%s%s",Hdrs[DATE],ptime(&t));
  1492.     fprintf(tfile,"%s<%ld@%s>\n",Hdrs[MSGID],get_msgid(1),Hostname);
  1493.     fprintf(tfile,DAEMONSTR,Hdrs[FROM],Hostname);
  1494.     fprintf(tfile,"%s%s\n",Hdrs[TO],newto != NULLCHAR ? newto : to);
  1495.     fprintf(tfile,"%s%s\n\n",Hdrs[SUBJECT],
  1496.         bounce ? "Failed mail" : "Return receipt");
  1497.     if(bounce){
  1498.         fprintf(tfile,"  ===== transcript follows =====\n\n");
  1499.         for (; lp != NULLLIST; lp = lp->next)
  1500.             fprintf(tfile,"%s\n",lp->val);
  1501.         fprintf(tfile,"\n");
  1502.     }
  1503.     fprintf(tfile,"  ===== %s follows ====\n",
  1504.         bounce ? "Unsent message" : "Message header");
  1505.  
  1506.     while(fgets(buf,sizeof(buf),data) != NULLCHAR){
  1507.         if(buf[0] == '\n')
  1508.             break;
  1509.         fputs(buf,tfile);
  1510.     }
  1511.     if(bounce){
  1512.         fputc('\n',tfile);
  1513.         while((cnt = fread(buf,1,sizeof(buf),data)) > 0)
  1514.             fwrite(buf,1,cnt,tfile);
  1515.     }
  1516.     fseek(tfile,0L,0);
  1517.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  1518.     (void) mailuser(tfile,"",newto != NULLCHAR ? newto : to,newto != NULLCHAR ? newto : to);
  1519.     fclose(tfile);
  1520.     free(newto);
  1521.     return 0;
  1522. }
  1523. #ifdef MSDOS
  1524. static int
  1525. dosfnchr(ch)
  1526. int ch;
  1527. {
  1528.     int i, j;
  1529.  
  1530.     i = (ch & 0xf8) >> 3;
  1531.     j = doschars[i] & (1 << (ch & 0x07));
  1532.     return j;
  1533. }
  1534. #endif
  1535.